import socket
import threading
import ipaddress
import os
import json

def is_valid_ip(ip_str):
    try:
        # 使用ipaddress库的ip_address方法尝试解析IP地址
        ipaddress.ip_address(ip_str)
        return True
    except ValueError:
        return False

# 获取本地主机名
hostname = socket.gethostname()
# 获取本地IP地址
localIP = socket.gethostbyname(hostname)
localPort = 8888
if os.path.exists("config.json"):
    with open("config.json", "r") as f:
        config:dict = json.load(f)
    if "LastRemoteIP" not in config.keys():
        config["LastRemoteIP"] = "0.0.0.0"
else:
    config = {}
    config["LastRemoteIP"] = "0.0.0.0"

# 本地IP和端口
# 获取本地主机名
hostname = socket.gethostname()
# 获取本地IP地址
localIP = socket.gethostbyname(hostname)
localPort = 8888
print(f"localIP:{localIP}, localPort: {localPort}")
print(f"LastIP:{config['LastRemoteIP']}")

# 远程IP和端口（ESP32的IP和端口）
while True:
    print(f"直接回车可填入上次连接的地址")
    remoteIP = input("输入机器人的IP地址: ")
    if is_valid_ip(remoteIP):
        print(f"\"{remoteIP}\" 是一个有效的IP地址")
        config["LastRemoteIP"] = remoteIP
        break
    elif remoteIP:
        print(f"\"{remoteIP}\" 不是一个有效的IP地址")
    else:
        remoteIP = config["LastRemoteIP"]
        if is_valid_ip(remoteIP):
            print(f"\"{remoteIP}\" 是一个有效的IP地址")
        break

# remoteIP = "192.168.0.107"
remotePort = 8888

# 创建UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((localIP, localPort))
sock.sendto(f"$0 {localIP}".encode(), (remoteIP, remotePort))

# 创建 UDP 广播套接字
sock_b = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 将套接字设置为广播模式
sock_b.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

# 监听UDP数据包的线程函数
def listen_thread():
    while True:
        # 从UDP套接字接收数据
        data, addr = sock.recvfrom(2048)
        try:
            _data = data.decode()
        except Exception as e:
            _data = str(e)
        print("\nReceived packet from {}:\n{}\nEnter message to send:".format(addr[0], _data), end="")

# 接收用户输入消息的线程函数
def input_thread():
    while True:
        # 通过input()函数接收用户输入的消息
        message = input("Enter message to send: ")
        # 发送数据到ESP32
        if message:
            if message.startswith("&"):
                sock_b.sendto(message.encode(), ("192.168.0.255", remotePort))
            else:
                sock.sendto(message.encode(), (remoteIP, remotePort))

def listen_forever():
    while True:
        # 从UDP套接字接收数据
        data, addr = sock.recvfrom(1024)
        print("\nReceived packet from {}: {}\nEnter message to send:".format(addr[0], data.decode()))

    # # 发送数据到ESP32
    # message = "Hello, ESP32!"
    # sock.sendto(message.encode(), (remoteIP, remotePort))

def start_two_thread():
    # 创建并启动监听线程和输入线程
    threading.Thread(target=listen_thread).start()
    threading.Thread(target=input_thread).start()

# if __name__ == "__main__":
start_two_thread()